package org.NooLab.nativebrowser;

import java.awt.Component;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

import jlibs.core.lang.JavaProcessBuilder;

import org.NooLab.nativebrowser.app.controller.parser.Page;
import org.NooLab.nativebrowser.app.controller.parser.PageIntf;
import org.NooLab.nativebrowser.browser.BrowserWorker;
import org.NooLab.nativebrowser.browser.DjBrowserListener;
import org.NooLab.nativebrowser.components.BrowserAppRecipientIntf;
import org.NooLab.nativebrowser.components.WebBrowserAppMainIntf;
import org.NooLab.nativebrowser.components.WebBrowserPublicIntf;
import org.NooLab.utilities.files.DFutils;
import org.NooLab.utilities.logging.LogControl;
import org.NooLab.utilities.logging.PrintLog;

import chrriis.dj.nativeswing.swtimpl.components.JWebBrowser;



/**
 * 
 * 
 * 
 *
 */
public class WebBrowserPublic 
								extends  
												Observable
								implements 
												WebBrowserPublicIntf,
												Observer{
	

	JavaProcessBuilder jvm;
	ArrayList<String> appArguments = new ArrayList<String>();
	
	static WebBrowserPublic exposedBrowser=null;
	WebBrowserAppMainIntf browserApp;
	private BrowserWorker swingWorker;
	String browserHtml = "";
	private static boolean isReady;
	
	String[] arguments;
	Observer externalObserver ;
	// WebBrowserAppMainIntf webBrowserApp ;
	WebBrowserAppMainIntf webBrowserApp;
	private Process process;
	private static WebBrowserPublic publicBrowserView;
	
	private Object exitValue;
	public static boolean internalProcess = true;

	
	PrintLog out = new PrintLog(2,false);
	private String appWorkingDir;
	private String jarFilePath;
	private String extLibPath;
	ArrayList<String> extLibPaths = new ArrayList<String>();
	private boolean appIsVisible=false;

	// ========================================================================
	protected WebBrowserPublic() {
		LogControl.Level = 1;
		WebBrowserApp.setLogControl(1);
	}

	
	public static WebBrowserPublicIntf open(  ) throws Exception {
		String[] args = new String[0] ;
		return open(false,args);
	}

	public static WebBrowserPublicIntf open( boolean asExternal ) throws Exception {
		String[] args = new String[0] ;
		return open(asExternal,args);
	}

	public static WebBrowserPublicIntf open(String[] args) throws Exception {
		return open(false,args);
	}
	
	private static WebBrowserPublicIntf open( boolean asExternal, String[] args) throws Exception {
		//
		PrintLog out = new PrintLog(2,false);
		
		WebBrowserPublic wbp ;
		
		if (publicBrowserView==null){
			wbp = new WebBrowserPublic();

			internalProcess = !asExternal;
			
			(new Starter(wbp, args)).start();
		
		 }else{	
			 publicBrowserView.reset();
			 return publicBrowserView; 
		 }
	
		
		// "isready" is set through... ?
		int z=0;
		while ((isReady==false) && (z<800)){
			out.delay(10);
		}
		
		if (isReady==false){
			throw(new Exception("WebBrowser could not be started by public interface."));
		}
		return publicBrowserView ;
	}


	@Override
	public void reset() {
		
		(new Starter(publicBrowserView, null)).reset();
	}
	
	@Override
	public void close() {
		
		webBrowserApp.close(1) ;
	}


	/*
		String cn;
		cn = sender.getClass().getName().toLowerCase();
		
		if (cn.contains("")==false){
			
		}
		
		PageIntf page = (PageIntf)data ;
		
		browserHtml = page.getHTML() ;
		
		setChanged();
		notifyObservers(browserHtml);
		
	}
	 */
	@Override
	public String navigate(String urlStr) {
		
		out.print(2, "Browser will navigate to url : "+urlStr);
		browserHtml="";
		// creating a new process, which will return only on completion (with a timeout)
		(new Navigator( webBrowserApp, 8000)).go(urlStr);
		
		while ((browserHtml==null) || (browserHtml.length()==0)){
			PrintLog.Delay(50);
		}
		
		if (appIsVisible){
			// webBrowserApp.getWebBrowser().setHTMLContent(browserHtml); 
			// JWebBrowser webbrowser, PageIntf page, DjBrowserListener listener
			PageIntf page = new Page();
			page.setHTML(browserHtml);
			page.setContextUrl(urlStr);
			DjBrowserListener listener = webBrowserApp.getWebBrowserHostInstance(0).getListener();
			listener.setInternalClient("display"); // secret for 
			(swingWorker = new BrowserWorker(  	webBrowserApp.getWebBrowser(),
												page, 
												listener  )).execute();
		}
		
		webBrowserApp.freeResources();
		return browserHtml;
	}


	@Override
	public void setMandatoryContentStr(String string) {
		// TODO Auto-generated method stub
		
	}


	@Override
	public void update(Observable sender, Object data) {
		// 
	
		// 
		out.print( 3, ">>>>>>>  message received from " + sender.toString());
		out.print( 3, ">>>>>>>  data section contains " + data.toString());
		
		PageIntf page = (PageIntf)data;
		browserHtml = page.getHTML();
		
		int n;
		n = browserHtml.length();
	}


	public void setBrowserApp(WebBrowserAppMainIntf webbrowser, WebBrowserPublic webBrowserPublic) {
		// 
		
		
		publicBrowserView = webBrowserPublic;
		webBrowserApp = webbrowser;
		
		webBrowserApp.setExternalObserver( this ) ;
		
	}


	protected void setReference(WebBrowserAppMainIntf app){
		this.webBrowserApp = app;
	}
	
	
 
	
	public static boolean isReady() {
		return isReady;
	}


	public void setReady(boolean isReady) {
		WebBrowserPublic.isReady = isReady;
	}


	public void setReadyState( boolean flag) {
		isReady = flag ;
		
		setChanged();
		notifyObservers((Long)1L);
	}

	

	@Override
	public void showDebug(int levelOfDetail) {
		LogControl.Level = levelOfDetail;
		WebBrowserApp.setLogControl(1);
	}


	@Override
	public void setVisible(boolean flag) {
		// 
		appIsVisible=flag;
		WebBrowserApp.setVisible(flag);
	}
	
	
	public void launch() throws Exception{
		

		createJVM();
		
		// to get the created command:
		String command[] = jvm.command();

		process = jvm.launch(System.out, System.err);
		out.delay(500);
		// to launch it
		
		 //Read out dir output
        InputStream is = process.getInputStream();
        
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);
        String line;
        
        System.out.printf("Output of running %s is:\n",  Arrays.toString(command));
        
        String processName = "browser";//getArgumentValueStr( arguments, "-name"); 
        
        while ((line = br.readLine()) != null) {
        	
        	if (line.contains("@iTexx")){
        		// new CoWorkerMsgDigest( itexx,this, CoWorkerIntf._mainServerPort, line);
        	}else{
        		System.out.println(line);
        	}
        }
		
		//Wait to get exit value
        try {

        	exitValue = process.waitFor();
            
            System.out.println("\n\nExit Value of process <"+processName+"> is "+exitValue);
            												
        } catch (Exception e) {
            e.printStackTrace();
        }
	}


	private void createJVM() throws IOException{
		// 
			
			jvm = new JavaProcessBuilder();
			
			jvm.initialHeap(512); // or jvm.initialHeap("512m");
			jvm.maxHeap(1424); // or jvm.maxHeap("1024m");
			 
			
			
			jvm.workingDir(new File(appWorkingDir));
			
			String jarCP = (new DFutils()).createpath(jarFilePath, "NooLabNativeBrowser.jar") ;
			jvm.classpath( new File(jarCP)) ; // relative path from configured working dir
			
			// jvm.classpath( classPaths );
			// jvm.libraryPath( new File(jarFilePath)) ; // 
			
			jvm.extDir(new File(extLibPath));
			for (int i=0;i<extLibPaths.size();i++){
				jvm.libraryPath(new File(extLibPaths.get(i)));
			}
			jvm.endorsedDir(new File(extLibPath));
			
			List<File> classpath = jvm.classpath();
			for (int i=0;i<classpath.size();i++){
				// parent.out.print(2, classpath.get(i).getAbsolutePath() ) ;
			}
			
			// to configure mainclass and its arguments
			jvm = jvm.mainClass("WebBrowserApp");// "example.MyTest") ;x
			
			// jvm.arg("-xvf");
			// jvm.arg("testDir");
			for (int i=0;i<appArguments.size();i++){
				jvm.arg( appArguments.get(i) );
			}
			
			
		}

		
	
	
}



class Starter implements Runnable, BrowserAppRecipientIntf{

	boolean isReady = false;
	Thread wbsThrd;
	WebBrowserPublic webBrowserPublic;
	
	
	
	
	public Starter(WebBrowserPublic wbp, String[] args){
		webBrowserPublic = wbp;
		wbp.arguments = args;
		
		wbsThrd = new Thread(this,"wbsThrd") ; 	
	}
	public void reset() {
		
		webBrowserPublic.webBrowserApp.reset(this) ;
		
	}
	public void start(){
		wbsThrd.start() ;
	}
	
	@Override
	public void run() {
	
		//if (webBrowserPublic.internalProcess)
		// reusing does not work...
		if (webBrowserPublic.webBrowserApp==null){
				WebBrowserApp.getInstance(webBrowserPublic.arguments, this);
			
		 //}else{ webBrowserPublic.webBrowserApp.reset(this) ;		}
			
		}else{
			
		}
		// this will return its instance through the Observer!
		
		//if (webBrowserPublic.webBrowserApp==null){
			System.err.println("...waiting for webbrowser...");

			int z = 0;
			while ((z < 100) && (webBrowserPublic.webBrowserApp == null)) {
				PrintLog.Delay(100);
				z++;
			}
				
		if (webBrowserPublic.webBrowserApp==null){
			System.err.println("WebBrowser could not be started!");
			
		}
	}
	
	
	@Override
	public void setBrowserApp(WebBrowserApp browserApp) {
		// 
		webBrowserPublic.webBrowserApp = browserApp;
		if (webBrowserPublic.webBrowserApp!=null){
	
			webBrowserPublic.setBrowserApp( webBrowserPublic.webBrowserApp,     // provided by the app
											webBrowserPublic); // routed through
			webBrowserPublic.setReady(true);
		}	
		
	}
	
	
}



class Navigator implements Runnable{

	private BrowserWorker swingWorker;
	String urlStr="";
	WebBrowserAppMainIntf webBrowserApp;
	
	Thread navThrd;
	// ----------------------------------------------------
	public Navigator( WebBrowserAppMainIntf browserApp, int timeout) {
		
		navThrd = new Thread(this,"navThrd");
		webBrowserApp = browserApp ;
	}
	// ----------------------------------------------------
	
	public String getHtml(){
		return "";
	}
	public void go( String urlstr ) {
		
		urlStr = urlstr;
		navThrd.start();
	}
	
	@Override
	public void run() {
		// 
		
		
		(swingWorker = new BrowserWorker(null, webBrowserApp.getWebBrowser(), urlStr)).execute();
		
		
		
	}
	
	
	
	
}